﻿// owner 蒋家伟

#pragma once
#include <type_traits>
#include <memory>

namespace jsdk
{
    // 智能指针，与unique_ptr使用相同
    // 再次封装的原因: unique_ptr中的const与非const 的 get 方法返回的结果只与原始类型T相关与使用场景无关，而使用时则期望如果unique_ptr本身是const时，get对象也不应该被修改，因此重新封装
    template<typename T, typename D = std::default_delete<T>>
    class OwnerPtr
    {
        static_assert(!std::is_pointer<T>::value && !std::is_reference<T>::value, "不应该用指针或者引用作为ownerptr的值类型");
        static_assert(!std::is_array<T>::value, "值类型不应该为数组");
    public:
        using valueType = typename T;
        using deleteType = typename D;
        using pointer = typename valueType*;
        using const_pointer = typename const valueType*;
        using Myt = typename OwnerPtr<valueType, deleteType>;

    public:
        constexpr OwnerPtr() noexcept{}
        constexpr OwnerPtr(std::nullptr_t) noexcept {}
        ~OwnerPtr() noexcept{}
        OwnerPtr(Myt&& roptr){
            m_upointer.swap(roptr.m_upointer);
        }

        template<typename T2, typename D2>
        OwnerPtr(OwnerPtr<T2, D2>&& opRight){
            static_assert(std::is_base_of<valueType, T2>::value,
                "T2 类型应该为 T的子类"
                );
            this->reset(opRight.release());
            this->get_deleter() = std::forward<D2>(opRight.get_deleter());
        }

        explicit OwnerPtr(pointer ptr) noexcept:
            m_upointer(ptr) {}

        explicit OwnerPtr(pointer ptr, const deleteType& deleter) noexcept :
            m_upointer(ptr, deleter)  {}

        OwnerPtr(const Myt& optr) = delete;
        OwnerPtr& operator=(const Myt& optr) = delete;

        const deleteType& get_deleter() const noexcept{
            return m_upointer.get_deleter();
        }

        deleteType& get_deleter() noexcept {
            return m_upointer.get_deleter();
        }

    public:
        operator bool() const {
            return this->get() != nullptr;
        }

        bool operator==(std::nullptr_t) const {
            return this->get() == nullptr;
        }

        bool operator!=(std::nullptr_t) const {
            return this->get() != nullptr;
        }

        valueType& operator*(){
            return *(this->get());
        }

        const valueType& operator*() const {
            return *(this->get());
        }

        pointer operator->(){
            return this->get();
        }

        const_pointer operator->() const {
            return this->get();
        }

        const_pointer get() const { return m_upointer.get(); }
        pointer get() { return m_upointer.get(); }

    public:
        void reset(pointer ptr = nullptr)
        {
            m_upointer.reset(ptr);
        }

        void swap(Myt& optr)
        {
            m_upointer.swap(optr.m_upointer);
        }

        pointer release() noexcept
        {
            return m_upointer.release();
        }

    private:
        bool operator<(const Myt&) = delete;
        bool operator>(const Myt&) = delete;

    private:
        std::unique_ptr<valueType, deleteType> m_upointer = nullptr;
    };
}

